using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using AlgLrnLib.Sorting;

namespace AlgLrn
{
    public partial class frmSort : Form
    {
        #region Private Fields
        private int _traceIndex;
        #endregion

        #region Constructors
        public frmSort()
        {
            InitializeComponent();
            _traceIndex = 0;
        }
        #endregion

        #region Event Handlers
        private void frmMain_Load(object sender, EventArgs e)
        {
            cbbxSortingType.SelectedIndex = Constants.MergeSort;

            ResetGUI();
        }

        private void btnSort_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtInput.Text.Trim()))
                return;

            int[] numbers = PrepareNumbers(txtInput.Text.Trim());

            if (numbers == null)
                return;

            SortThreadData td = new SortThreadData(numbers, cbbxSortingType.SelectedIndex, rbtnAsc.Checked);
            ClearOutput();
            bwSortThread.RunWorkerAsync(td);

            ResetGUI();
        }

        private void frmMain_ResizeEnd(object sender, EventArgs e)
        {
            if (this.Width < Constants.MinFormWidth)
                this.Width = Constants.MinFormWidth;

            if (this.Height < Constants.MinFormHeight)
                this.Height = Constants.MinFormHeight;
        }

        private void bwSortThread_DoWork(object sender, DoWorkEventArgs e)
        {
            SortThreadData td = (SortThreadData)e.Argument;

            e.Result = Sort(td);
        }

        private void bwSortThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            string traceinfo = (string)e.UserState;
            txtItterations.Text += traceinfo + "\r\n";
        }

        private void bwSortThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            int[] numbers = (int[])e.Result;
            txtResult.Text = BuildOutput(numbers);
            ResetGUI();
        }
        #endregion

        #region Private Members
        private int[] PrepareNumbers(string numbers)
        {
            string[] numbersStrArr = numbers.Split(',');
            int[] numbersArr = new int[numbersStrArr.Length];
            int i = 0;
            foreach (string number in numbersStrArr)
            {
                int nNumber;
                if (!Int32.TryParse(number, out nNumber))
                    return null;

                numbersArr[i] = nNumber;
                i++;
            }

            return numbersArr;
        }

        private int[] Sort(SortThreadData td)
        {
            int[] retVal = null;
            BaseSort sort = null;

            switch (td.SortingType)
            {
                case Constants.InsertionSort:
                    sort = new InsertionSort();

                    if (td.SortAscending)
                        retVal = sort.SortAsc(td.Numbers, DebugTrace);
                    else
                        retVal = sort.SortDesc(td.Numbers, DebugTrace);

                    break;
                case Constants.SelectionSort:
                    sort = new SelectionSort();

                    if (td.SortAscending)
                        retVal = sort.SortAsc(td.Numbers, DebugTrace);
                    else
                        retVal = sort.SortDesc(td.Numbers, DebugTrace);

                    break;
                case Constants.MergeSort:
                    sort = new MergeSort();

                    if (td.SortAscending)
                        retVal = sort.SortAsc(td.Numbers, DebugTrace);
                    else
                        retVal = sort.SortDesc(td.Numbers, DebugTrace);

                    break;
                default:
                    break;
            }

            return retVal;
        }

        private string BuildOutput(int[] numbers)
        {
            StringBuilder strBld = new StringBuilder();
            foreach (double number in numbers)
                strBld.Append(string.Format("{0}, ", number));

            return strBld.ToString().Substring(0, strBld.Length - 2);
        }

        private void ResetGUI()
        {
            btnSort.Enabled = !bwSortThread.IsBusy && cbbxSortingType.SelectedIndex > -1;
        }

        private void DebugTrace(int[] numbers, string notes, bool withClear)
        {
            if (!cbbxDumpSteps.Checked)
            {
                ClearOutput();
                return;
            }

            if (withClear)
            {
                ClearOutput();
                _traceIndex = 0;
            }

            _traceIndex++;

            StringBuilder sbldNumber = new StringBuilder();

            foreach (double number in numbers)
                sbldNumber.Append(string.Format("{0},", number));

            string strNumber = sbldNumber.ToString();
            strNumber = strNumber.Substring(0, strNumber.Length - 2);

            if (!string.IsNullOrEmpty(notes))
                strNumber = string.Format("{0:d4}. {1} -> {2}", _traceIndex, strNumber, notes);

            if (bwSortThread != null && bwSortThread.IsBusy && !bwSortThread.CancellationPending)
                bwSortThread.ReportProgress(0, strNumber);
        }

        private void ClearOutput()
        {
            txtItterations.Text = string.Empty;
            txtResult.Text = string.Empty;
        }
        #endregion
    }
}
